Add openai_agents streaming sample - #301
Conversation
Demonstrates buffered token streaming for OpenAI Agents-backed workflows via temporalio.contrib.workflow_streams (experimental, contrib/pubsub branch of sdk-python). The OpenAI Agents plugin's ModelActivityParameters carries a streaming_event_topic; the model activity publishes raw stream events to that topic with a configurable flush interval (default 100ms), and the workflow emits a sentinel on a "done" topic when Runner.run_streamed finishes. Subscribers iterate (events, done) and break on the sentinel — race_with_workflow handles the case where the workflow fails before publishing the sentinel. Two scenarios: - stream_text: text-delta events from a simple haiku agent - stream_items: agent-update / handoff / tool-call events across a multi-agent workflow with a joke-rating activity
run_stream_items_workflow: print the workflow's final result after the streamed events render — matches run_stream_text_workflow and makes streamed-vs-final parity visible.
The sample was written against the contrib/pubsub branch of sdk-python. Workflow Streams and OpenAI Agents streaming both shipped in 1.30.0, with some renames and one behavioral difference, so bring the sample in line: - ModelActivityParameters.streaming_event_topic is now streaming_topic, and streaming_event_batch_interval is streaming_batch_interval. - subscribe() without result_type decodes payloads rather than handing back a raw Payload. Pass result_type=RawValue and decode per topic, matching the workflow_streams samples. - subscribe() exits cleanly once the workflow reaches a terminal state, so the race_with_workflow helper is unnecessary: break on the terminator, then await handle.result(), which raises if the workflow failed. Verified against a terminated workflow. - Workflows hold the run open briefly after publishing the terminator so a subscriber's next poll can drain the tail of the stream, which lives in workflow memory. Fix the stream_items scenario. The streaming activity publishes native OpenAI events, not the agents-SDK StreamEvent wrappers, so the agent-update / tool-call / message-output events the subscriber was matching on never appear on that topic. The agents SDK builds those inside the workflow, so the workflow now publishes them itself as a serializable ItemEvent on its own topic (the SDK's own event types carry the originating Agent, which holds tool callables). stream_events() resolves a turn at a time, so the play-by-play still arrives progressively. For the same reason, the stream_text subscriber now matches ResponseTextDeltaEvent directly instead of unwrapping a raw_response_event. Also move both workflow module docstrings above the imports, where they are actually docstrings, and drop the stale contrib/pubsub install notes from the READMEs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Covers both scenarios against a scripted streaming model, so no OPENAI_API_KEY is needed: the plugin accepts a model_provider directly, so unlike the other AI sample tests this one needs no monkeypatching. - stream_text: the text arrives as several native OpenAI delta events that reassemble into exactly what the workflow returns. - stream_items: the workflow-published events arrive in order — agent_updated, tool_call, tool_output, message_output. Both subscribe the same way the runner scripts do (one iterator over the event and terminator topics, RawValue payloads decoded per topic) and assert the terminator is seen, which is what lets the subscriber stop without racing the workflow's completion. These are the first tests under tests/openai_agents. The directory should also be listed in CODEOWNERS alongside the other AI sample test directories, but this branch predates that block, so adding it here would conflict with main. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Matches the other AI sample test directories. Deferred until after the merge from main, which is where that block came from. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Picked this up to get it over the line. Four commits pushed on top of yours (nothing rewritten, main merged in rather than rebased). The PR description above is now stale — summary of what changed: Updated for the released APIWorkflow Streams and OpenAI Agents streaming both shipped in
|
There was a problem hiding this comment.
Pull request overview
Adds a new openai_agents/streaming/ sample showing how to expose buffered model token streaming from OpenAI Agents-backed workflows to external subscribers using temporalio.contrib.workflow_streams, plus tests and supporting mock model infrastructure.
Changes:
- Introduces two streaming workflows (
stream_text,stream_items) and runnable scripts to start a worker and subscribe to streamed output. - Adds a dedicated README explaining buffered token streaming semantics, topics, and subscriber patterns.
- Adds automated tests for both streaming scenarios, including a scripted streaming model provider for deterministic test runs.
Reviewed changes
Copilot reviewed 12 out of 16 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
tests/openai_agents/streaming_test.py |
End-to-end tests that subscribe to workflow streams and assert streamed event shapes and final results. |
tests/openai_agents/_mock_model.py |
Scripted streaming ModelProvider used by tests to deterministically emit deltas, tool calls, and completion events. |
tests/openai_agents/__init__.py |
Marks tests.openai_agents as a package for test imports. |
openai_agents/streaming/workflows/stream_text_workflow.py |
Workflow that runs an agent via Runner.run_streamed and publishes a completion sentinel for subscribers. |
openai_agents/streaming/workflows/stream_items_workflow.py |
Workflow that publishes higher-level agent/tool/message events to its own stream topic while the run progresses. |
openai_agents/streaming/workflows/__init__.py |
Marks workflows directory as a package. |
openai_agents/streaming/shared.py |
Shared constants (task queue, topic names, drain interval) and a serializable ItemEvent type. |
openai_agents/streaming/run_worker.py |
Worker entrypoint registering workflows/activities and configuring the plugin’s streaming topic. |
openai_agents/streaming/run_stream_text_workflow.py |
Starter/subscriber script that renders ResponseTextDeltaEvent output as it streams. |
openai_agents/streaming/run_stream_items_workflow.py |
Starter/subscriber script that prints higher-level workflow-published ItemEvents. |
openai_agents/streaming/README.md |
Documentation for buffered streaming behavior, configuration, and how the sample is structured. |
openai_agents/streaming/activities/joke_activities.py |
Small activity used as a tool in the multi-agent streaming example. |
openai_agents/streaming/activities/__init__.py |
Marks activities directory as a package. |
openai_agents/streaming/__init__.py |
Marks streaming sample directory as a package. |
openai_agents/README.md |
Adds the new Streaming sample to the OpenAI Agents samples index. |
.github/CODEOWNERS |
Assigns code ownership for tests/openai_agents/ to the AI SDK owners. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
Adds an
openai_agents/streaming/sample demonstrating buffered token streaming for OpenAI Agents-backed workflows viatemporalio.contrib.workflow_streams(experimental,contrib/pubsubbranch of sdk-python).The OpenAI Agents plugin's
ModelActivityParameterscarries astreaming_event_topic; the model activity publishes rawTResponseStreamEvents to that topic, batched overstreaming_event_batch_interval(default 100ms). The workflow emits a sentinel on adonetopic whenRunner.run_streamedfinishes; subscribers iterate(events, done)and break on the sentinel.race_with_workflowhandles the case where the workflow fails before publishing the sentinel.Two scenarios:
stream_text— text-delta events from a simple haiku agentstream_items— agent-update / handoff / tool-call events across a multi-agent workflow with a joke-rating activityThis is the second half of #299. Independent of the workflow_streams basics (separate PR), though both target the same sdk-python contrib branch.
Test plan
contrib/pubsuband install into the samples uv environmentOPENAI_API_KEY=... uv run openai_agents/streaming/run_worker.pyuv run openai_agents/streaming/run_stream_text_workflow.py— verify text deltas print as small burstsuv run openai_agents/streaming/run_stream_items_workflow.py— verify agent-update / tool-call / message-output events render in order